/************************************************************************
* meshgen_utils.c
* voxelands - 3d voxel world sandbox game
* Copyright (C) Lisa 'darkrose' Milne 2016 <lisa@ltmnet.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>
************************************************************************/

#include "common.h"
#include "graphics.h"

#include "meshgen.h"

static block_t ignore_block = {
	CONTENT_IGNORE,
	0,0,0
};


/* check if the dir face of b1 should be drawn based on the content of b2 */
/* TODO: there may be other cases that should return false */
uint8_t meshgen_hardface(block_t *b1, block_t *b2, uint8_t dir)
{
/*	contentfeatures_t *f1;*/
	contentfeatures_t *f2;

/*	f1 = content_features(b1->content);*/
	f2 = content_features(b2->content);

	if (!f2)
		return 1;

	if (f2->draw_type == CDT_CUBELIKE || f2->draw_type == CDT_DIRTLIKE)
		return 0;

/*
	if (f2->draw_type == CDT_STAIRLIKE) {
		bool urot = (nn.getContent() >= CONTENT_SLAB_STAIR_UD_MIN && nn.getContent() <= CONTENT_SLAB_STAIR_UD_MAX);
		if ((urot && pos.Y == -1) || (!urot && pos.Y == 1))
			return false;
		if (unpackDir(nn.param1) == ipos)
			return false;
		bool furot = (n.getContent() >= CONTENT_SLAB_STAIR_UD_MIN && n.getContent() <= CONTENT_SLAB_STAIR_UD_MAX);
		if (f1->draw_type == CDT_STAIRLIKE && furot == urot && nn.param1 == n.param1)
			return false;
		if (f1->draw_type == CDT_SLABLIKE && furot == urot && unpackDir(nn.param1) == pos)
			return false;
	}
	if (f2->draw_type == CDT_SLABLIKE && f1->draw_type == CDT_SLABLIKE) {
		bool urot = (nn.getContent() >= CONTENT_SLAB_STAIR_UD_MIN && nn.getContent() <= CONTENT_SLAB_STAIR_UD_MAX);
		if ((urot && pos.Y == 1) || (!urot && pos.Y == -1))
			return false;
		if (!pos.Y && n.getContent() == nn.getContent())
			return false;
	}
	if (f2->draw_type == CDT_MELONLIKE) {
		if (f2->param2_type != CPT_PLANTGROWTH || nn.param2 == 0)
			return false;
	}
*/
	return 1;
}

/* layer for getting a block will do it fast if possible, otherwise will grab from the map */
block_t *meshgen_get_block(chunk_t *ch, pos_t *p, uint8_t only_chunk)
{
	if (p->x < 0 || p->x > 15 || p->y < 0 || p->y > 15 || p->z < 0 || p->z > 15) {
		pos_t bp;
		block_t *b;
		if (only_chunk)
			return &ignore_block;
		bp.x = ch->pos.x + p->x;
		bp.y = ch->pos.y + p->y;
		bp.z = ch->pos.z + p->z;
		b = map_get_block(&bp);
		if (b)
			return b;
		return &ignore_block;
	}

	return &ch->blocks[p->x][p->y][p->z];
}

/* get the hardface data for each face of block */
void meshgen_hardfaces(chunk_t *ch, block_t *b, pos_t *p, uint8_t f[6])
{
	block_t *bb;
	pos_t pp;
	pos_t pi[6] = {
		{0,0,-1},
		{0,0,1},
		{1,0,0},
		{-1,0,0},
		{0,1,0},
		{0,-1,0}
	};
	uint8_t di[6] = {
		MAP_NORTH,
		MAP_SOUTH,
		MAP_EAST,
		MAP_WEST,
		MAP_UP,
		MAP_DOWN
	};
	int i;

	for (i=0; i<6; i++) {
		f[i] = 1;
		pp.x = p->x+pi[i].x;
		pp.y = p->y+pi[i].y;
		pp.z = p->z+pi[i].z;
		if (pp.x < 0 || pp.x > 15 || pp.y < 0 || pp.y > 15 || pp.z < 0 || pp.z > 15) {
			bb = &ignore_block;
		}else{
			bb = &ch->blocks[pp.x][pp.y][pp.z];
		}
		f[i] = meshgen_hardface(b,bb,di[i]);
	}
}

/* get and/or create the mesh for a block face */
mesh_t *meshgen_get_mesh(mapobj_t *o, block_t *b, uint8_t face, uint8_t lod)
{
	array_t *ma;
	int i;
	material_t *mat;
	mesh_t *m = NULL;
	contentfeatures_t *f;

	f = content_features(b->content);
	if (!f)
		return NULL;

	switch (face) {
	case MAP_NORTH:
		mat = array_get_ptr(&f->materials,CT_BACK0);
		if (!mat)
			mat = array_get_ptr(&f->materials,CT_SIDES0);
		if (!mat)
			mat = array_get_ptr(&f->materials,CT_BASE0);
		break;
	case MAP_SOUTH:
		mat = array_get_ptr(&f->materials,CT_FRONT0);
		if (!mat)
			mat = array_get_ptr(&f->materials,CT_SIDES0);
		if (!mat)
			mat = array_get_ptr(&f->materials,CT_BASE0);
		break;
	case MAP_EAST:
		mat = array_get_ptr(&f->materials,CT_RIGHT0);
		if (!mat)
			mat = array_get_ptr(&f->materials,CT_SIDES0);
		if (!mat)
			mat = array_get_ptr(&f->materials,CT_BASE0);
		break;
	case MAP_WEST:
		mat = array_get_ptr(&f->materials,CT_LEFT0);
		if (!mat)
			mat = array_get_ptr(&f->materials,CT_SIDES0);
		if (!mat)
			mat = array_get_ptr(&f->materials,CT_BASE0);
		break;
	case MAP_UP:
		mat = array_get_ptr(&f->materials,CT_TOP0);
		if (!mat)
			mat = array_get_ptr(&f->materials,CT_BASE0);
		break;
	case MAP_DOWN:
		mat = array_get_ptr(&f->materials,CT_BOTTOM0);
		if (!mat)
			mat = array_get_ptr(&f->materials,CT_BASE0);
		break;
	default:
		return NULL;
	}

	if (!mat)
		return NULL;

	ma = o->objs[lod].meshes;
	if (!ma) {
		o->objs[lod].meshes = array_create(ARRAY_TYPE_PTR);
		ma = o->objs[lod].meshes;
	}else{
		mesh_t **d = ma->data;
		for (i=0; i<ma->length; i++) {
			m = d[i];
			if (m->mat->id == mat->id)
				return m;
		}
	}

	m = mesh_create_material(mat);
	array_push_ptr(ma,m);

	return m;
}
